


import 'dart:convert';

import 'package:bt_tool/basic/bt_controller.dart';
import 'package:bt_tool/basic/bt_json_tool.dart';
import 'package:bt_tool/basic/bt_model.dart';
import 'package:bt_tool/basic/bt_utils.dart';
import 'package:bt_tool/widget/bt_text_field.dart';
import 'package:bt_tool/widget/bt_toast.dart';
import 'package:crypto/crypto.dart';
import 'package:flutter/services.dart';
import 'package:flutter_demo/tools/json/json_main_model.dart';
import 'package:get/get.dart';


enum ToolsJsonType{
  flutter(0),
  objectC(1),
  swift(2),
  swiftObjectC(3);
  final int iValue;
  const ToolsJsonType(this.iValue);
  static ToolsJsonType fromInt(int value) {
    switch (value) {
      case 0:
        return ToolsJsonType.flutter;
      case 1:
        return ToolsJsonType.objectC;
      case 2:
        return ToolsJsonType.swift;
      case 3:
        return ToolsJsonType.swiftObjectC;
      default:
        return ToolsJsonType.swift;
    }
  }
}

class JsonMainController extends BTController{

  final BTTextFieldController inputCtl = BTTextFieldController();
  final BTTextFieldController resultCtl = BTTextFieldController();
  final BTTextFieldController baseCtl = BTTextFieldController();
  final resultList = <JsonMainModel>[].obs;
  var selectFileIndex = 0.obs;
  var jsonType = ToolsJsonType.flutter.obs;

  @override
  dispose() {
    inputCtl.dispose();
    resultCtl.dispose();
    baseCtl.dispose();
    super.dispose();
  }

  convert(){
    String text = inputCtl.getText();
    String baseName = baseCtl.getText();
    if(text.isEmpty){
      selectFileIndex.value = 0;
      resultList.clear();
      resultCtl.updateText("");
      return;
    }
    if(baseName.isEmpty){
      baseName = "Base";
    }else{
      baseName = BTUtils.capitalizeFirstLetter(baseName);
    }
    var map = BTJsonTool.convertStrToMap(text,errorCallback: (errorStr){
      BTToast.showToast(errorStr);
    });
    if(map.isEmpty){
      return;
    }
    resultCtl.updateText("");
    selectFileIndex.value = 0;
    resultList.clear();



    if(jsonType.value == ToolsJsonType.flutter){
      covertNextFlutter(map,resultList,baseName);
    }else if(jsonType.value == ToolsJsonType.objectC){
      convertNextObjc(map,resultList,baseName);
    }else if(jsonType.value == ToolsJsonType.swift){
      convertNextSwift(map, resultList, baseName);
    }else if(jsonType.value == ToolsJsonType.swiftObjectC){
      convertNextSwift(map, resultList, baseName);
    }
    changeIndex(0);

  }

  defaultTest() async {
    String jsonStr = await rootBundle.loadString("resource/bt_test_json.json");
    inputCtl.updateText(jsonStr);
    convert();
  }

  String appendModelStr(String name){
    return "${name}Model";
  }

  covertNextFlutter(Map<String,dynamic> map,List<JsonMainModel> list,String fileName){
    JsonMainModel jsonModel = JsonMainModel();
    jsonModel.fileName = fileName;

    for(var key in map.keys){
      var obj = map[key];
      var objType = BTModel.getFieldType(obj);
      var parameterStr = "";
      var parseStr = "";
      var toMapStr = "";
      if(objType == BTModelFieldType.stringType){
        parameterStr = "String $key = \"\";";
        parseStr = "$key = jsonTool.getString(\"$key\");";
        toMapStr = "dict[\"$key\"] = $key;";
      }else if(objType == BTModelFieldType.intType){
        parameterStr = "int $key = 0;";
        parseStr = "$key = jsonTool.getInt(\"$key\");";
        toMapStr = "dict[\"$key\"] = $key;";
      }else if(objType == BTModelFieldType.boolType){
        parameterStr = "bool $key = false;";
        parseStr = "$key = jsonTool.getBool(\"$key\");";
        toMapStr = "dict[\"$key\"] = $key;";
      }else if(objType == BTModelFieldType.doubleType){
        parameterStr = "double $key = 0.0;";
        parseStr = "$key = jsonTool.getDouble(\"$key\");";
        toMapStr = "dict[\"$key\"] = $key;";
      }else if(objType == BTModelFieldType.mapType){
        String subModelName = fileName + BTUtils.capitalizeFirstLetter(key);
        parameterStr = "${appendModelStr(subModelName)} $key = ${appendModelStr(subModelName)}(null);";
        parseStr = "$key = ${appendModelStr(subModelName)}(jsonTool.getMap(\"$key\"));";
        covertNextFlutter(obj as Map<String,dynamic>, list, subModelName);
        toMapStr = "dict[\"$key\"] = $key.convertToDict();";
      }else if(objType == BTModelFieldType.listType){
        List subList = obj;
        while(subList.first is List){
          subList = subList.first;
        }

        bool isAllListChildSameCla = true;
        var objFirst = subList.first;
        for(var objSub in subList){
          if(objFirst.runtimeType != objSub.runtimeType){
            isAllListChildSameCla = false;
          }
        }

        String subModelName = fileName + BTUtils.capitalizeFirstLetter(key);
        if(isAllListChildSameCla){
          if(subList.first is String){
            parameterStr = "List<String> $key = [];";
            parseStr = "$key = jsonTool.getStrList(\"$key\");";
            toMapStr = "dict[\"$key\"] = $key;";
          }else if(subList.first is Map){
            String subClasName = appendModelStr(subModelName);
            parameterStr = "List<${appendModelStr(subModelName)}> $key = [];";
            parseStr = "for(var map in jsonTool.getMapList(\"$key\")){\n$subClasName model = $subClasName(map);\n$key.add(model);\n}";
            covertNextFlutter(subList.first, list, subModelName);
            toMapStr = "dict[\"$key\"] = convertModelListToDictList($key);";
          }else if(subList.first is int){
            parameterStr = "List<int> $key = [];";
            parseStr = "$key = jsonTool.getIntList(\"$key\");";
            toMapStr = "dict[\"$key\"] = $key;";
          }else if(subList.first is bool){
            parameterStr = "List<bool> $key = [];";
            parseStr = "$key = jsonTool.getBoolList(\"$key\");";
            toMapStr = "dict[\"$key\"] = $key;";
          }else if(subList.first is double){
            parameterStr = "List<double> $key = [];";
            parseStr = "$key = jsonTool.getDoubleList(\"$key\");";
            toMapStr = "dict[\"$key\"] = $key;";
          }else{
            parameterStr = "List<dynamic> $key = [];";
            parseStr = "$key = jsonTool.getList(\"$key\");";
            toMapStr = "dict[\"$key\"] = $key;";
          }
        }else{
          parameterStr = "List<dynamic> $key = [];";
          parseStr = "$key = jsonTool.getList(\"$key\");";
          toMapStr = "dict[\"$key\"] = $key;";
        }





        // parseStr = "$parseStr\nfor(var m in {$key}MapList)\n{\n var model = }";

      }else{
        parameterStr = "dynamic $key;";
        parseStr = "$key = jsonTool.getDynamic(\"$key\");";
        toMapStr = "dict[\"$key\"] = $key;";
      }
      if(jsonModel.parameterStr.isEmpty){
        jsonModel.parameterStr = parameterStr;
      }else{
        jsonModel.parameterStr = "${jsonModel.parameterStr}\n$parameterStr";
      }

      if(jsonModel.parseStr.isEmpty){
        jsonModel.parseStr = parseStr;
      }else{
        jsonModel.parseStr = "${jsonModel.parseStr}\n$parseStr";
      }

      if(jsonModel.toMapStr.isEmpty){
        jsonModel.toMapStr = toMapStr;
      }else{
        jsonModel.toMapStr = "${jsonModel.toMapStr}\n$toMapStr";
      }

    }
    list.insert(0, jsonModel);
  }

  changeIndex(int index){
    selectFileIndex.value = index;
    resultCtl.updateText(resultList[index].getFullStr(jsonType.value));
  }

  convertNextObjc(Map<String,dynamic> map,List<JsonMainModel> list,String fileName){
    JsonMainModel jsonModel = JsonMainModel();
    jsonModel.fileName = fileName;

    for(var key in map.keys){
      var obj = map[key];
      var objType = BTModel.getFieldType(obj);
      var parameterStr = "";
      var ocClassDict = "";
      if(objType == BTModelFieldType.stringType){
        parameterStr = "@property (nonatomic) NSString * $key;";
      }else if(objType == BTModelFieldType.intType){
        parameterStr = "@property (nonatomic) NSInteger $key;";
      }else if(objType == BTModelFieldType.boolType){
        parameterStr = "@property (nonatomic) BOOL $key;";
      }else if(objType == BTModelFieldType.doubleType){
        parameterStr = "@property (nonatomic) CGFloat $key;";
      }else if(objType == BTModelFieldType.mapType){
        String subModelName = fileName + BTUtils.capitalizeFirstLetter(key);
        parameterStr = "@property (nonatomic) ${appendModelStr(subModelName)} * $key;";
        ocClassDict = "@\"$key\" : ${appendModelStr(subModelName)}.class,";
        convertNextObjc(obj, list, subModelName);
      }else if(objType == BTModelFieldType.listType){
        List subList = obj;
        while(subList.first is List){
          subList = subList.first;
        }
        String subModelName = fileName + BTUtils.capitalizeFirstLetter(key);
        if(subList.first is Map){
          parameterStr = "@property (nonatomic) NSArray<${appendModelStr(subModelName)}*> * $key;";
          convertNextObjc(subList.first, list, subModelName);
          ocClassDict = "@\"$key\" : ${appendModelStr(subModelName)}.class,";
        }else if(subList.first is String){
          parameterStr = "@property (nonatomic) NSArray<NSString*> * $key;";
        }else if(subList.first is int || subList.first is double || subList.first is bool){
          parameterStr = "@property (nonatomic) NSArray<NSNumber*> * $key;";
        }else{
          parameterStr = "@property (nonatomic) NSArray<NSObject*> * $key;";
        }

      }else{
        parameterStr = "@property (nonatomic) NSObject * $key;";

      }
      if(jsonModel.parameterStr.isEmpty){
        jsonModel.parameterStr = parameterStr;
      }else{
        jsonModel.parameterStr = "${jsonModel.parameterStr}\n$parameterStr";
      }

      if(ocClassDict.isNotEmpty){
        if(jsonModel.ocClassDict.isEmpty){
          jsonModel.ocClassDict = ocClassDict;
        }else{
          jsonModel.ocClassDict = "${jsonModel.ocClassDict}\n        $ocClassDict";
        }
      }
    }
    list.insert(0, jsonModel);
  }


  convertNextSwift(Map<String,dynamic> map,List<JsonMainModel> list,String fileName){
    JsonMainModel jsonModel = JsonMainModel();
    jsonModel.fileName = fileName;


    for(var key in map.keys){
      var obj = map[key];
      var objType = BTModel.getFieldType(obj);
      var parameterStr = "";
      var rangType = "open";
      var parseStr = "";
      var toMapStr = "";
      if(objType == BTModelFieldType.stringType){
        parameterStr = "$rangType var $key : String = \"\"";
        parseStr = "$key = jsonTool.getString(key: \"$key\")";
        toMapStr = "dict[\"$key\"] = $key";
      }else if(objType == BTModelFieldType.intType){
        parameterStr = "$rangType var $key : Int = 0";
        parseStr = "$key = jsonTool.getInteger(key: \"$key\")";
        toMapStr = "dict[\"$key\"] = $key";
      }else if(objType == BTModelFieldType.boolType){
        parameterStr = "$rangType var $key : Bool = false";
        parseStr = "$key = jsonTool.getBool(key: \"$key\")";
        toMapStr = "dict[\"$key\"] = $key";
      }else if(objType == BTModelFieldType.doubleType){
        parameterStr = "$rangType var $key : Double = 0.0";
        parseStr = "$key = jsonTool.getNumber(key: \"$key\").floatValue";
        toMapStr = "dict[\"$key\"] = $key";
      }else if(objType == BTModelFieldType.mapType){
        String subModelName = fileName + BTUtils.capitalizeFirstLetter(key);
        parameterStr = "$rangType var $key : ${appendModelStr(subModelName)}?";
        parseStr = "$key = ${appendModelStr(subModelName)}.init(dict:jsonTool.getDict(key: \"$key\"))";
        toMapStr = "dict[\"$key\"] = $key?.convertToDict()";
        // ocClassDict = "@\"$key\" : ${appendModelStr(subModelName)}.class,";
        convertNextSwift(obj, list, subModelName);
      }else if(objType == BTModelFieldType.listType){
        List subList = obj;
        while(subList.first is List){
          subList = subList.first;
        }
        String subModelName = fileName + BTUtils.capitalizeFirstLetter(key);
        if(subList.first is Map){
          parameterStr = "$rangType var $key : [${appendModelStr(subModelName)}] = []";
          convertNextSwift(subList.first, list, subModelName);
          parseStr = "for obj in jsonTool.getDictArray(key: \"$key\") {\n   $key.append(${appendModelStr(subModelName)}.init(dict:obj))\n}";
          toMapStr = "dict[\"$key\"] = convertModelListToDict(modelArray:$key)";
        }else if(subList.first is String){
          parameterStr = "$rangType var $key : [String] = []";
          parseStr = "$key = jsonTool.getStringArray(key: \"$key\")";
          toMapStr = "dict[\"$key\"] = $key";
        }else if(subList.first is int || subList.first is double || subList.first is bool){
          parameterStr = "$rangType var $key : [NSNumber] = []";
          toMapStr = "dict[\"$key\"] = $key";
        }else{
          parameterStr = "$rangType var $key : [Any] = []";
          parseStr = "$key = jsonTool.getArray(key: \"$key\")";
          toMapStr = "dict[\"$key\"] = $key";
        }

      }else{
        parameterStr = "$rangType var $key : Any?";
        parseStr = "$key = jsonTool.getObject(key: \"$key\")";
        toMapStr = "dict[\"$key\"] = $key";
      }
      if(jsonModel.parameterStr.isEmpty){
        jsonModel.parameterStr = parameterStr;
      }else{
        jsonModel.parameterStr = "${jsonModel.parameterStr}\n$parameterStr";
      }

      if(jsonModel.parseStr.isEmpty){
        jsonModel.parseStr = parseStr;
      }else{
        if(parseStr.isNotEmpty){
          jsonModel.parseStr = "${jsonModel.parseStr}\n$parseStr";
        }

      }

      if(jsonModel.toMapStr.isEmpty){
        jsonModel.toMapStr = toMapStr;
      }else{
        jsonModel.toMapStr = "${jsonModel.toMapStr}\n$toMapStr";

      }

    }


    list.insert(0, jsonModel);
  }
}